'reach 0.1';


//共有的对象方法//Fun([reach参数1,reach参数2,reach参数3,...reach参数n], reach接收返回数据类型,如果没有则是Null)
const commonHandle = {
    ...hasRandom,
    ...hasConsoleLogger,
    //支付超时处理
    payTimeoutHandle: Fun([], Null),
    //告诉玩家支付已经完成了，准备开始盖牌
    tellGameStartStatus: Fun([Bool], Null),
    //等到回合超时处理
    waitTimeoutHandle: Fun([], Null),
    //生成设置的隐藏盖牌角色卡
    getHideRoleHandle: Fun([], UInt),
    //初始化洗卡以及手牌
    setInitialHand: Fun([], UInt),

    //每个回合该玩家抽卡
    currentDrawCardAction: Fun([], Null),
    //思考，为什么要传限制卡？因为限制卡发动后会每个回合自减1，所以需要事先转换数据类型
    //当前回合该玩家的使用卡(按顺序返回，每个回合最多三张使用卡+玩家的判断结果，卡1的uuid，卡1的结算分数，卡1的类型状态（比如1是正，2是负...），...,限制卡uuid，限制卡的分数，限制卡的类型状态（比如1是正，2是负...）,玩家的判断状态码).
    currentUseCardAction: Fun([], Tuple(UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt)),
    //等待玩家的操作处理
    waitUseCardAction: Fun([UInt, UInt, UInt, UInt, UInt], Tuple(UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt, UInt)),
    //告诉当前回合玩家，等待另一个玩家的使用卡结果处理
    tellwaitplayerUseCardResult: Fun([UInt, UInt, UInt, UInt], Null),
    //告诉玩家当前回合时的状态(A分数，b分数，回合，倒数)
    tellEndRoundStatus: Fun([UInt, UInt, UInt, UInt, UInt, UInt], Null),
    //告诉玩家是最终的结果谁赢了
    tellWhoWinHandle: Fun([UInt, UInt, UInt, UInt], Null),


}


//属于建立房间卡组对象
const Oneself = {
    ...commonHandle,
    //对局代币数量
    wager: UInt,


}

//对手的卡组对象
const Opponent = {
    ...commonHandle,
    //获取对手代币数量
    getTokenNumberHandle: Fun([UInt], Null),
}

//定义一个支付超时的时间（10分钟？）
const OVERTIME_PAY = 10

//定义一个回合超时的时间 （5分钟？）
const OVERTIME_PLAY = 5

//numA1 与numA2 是A的分数与状态，numA1表示分数，numA2表示状态（0代表正数，1表示负数）
//numB1 与numB2 是B的分数与状态，numB1表示分数，numB2表示状态（0代表正数，1表示负数）
// A1是指A使用卡的结算分数，A2是指B使用卡的状态（0代表是正数，作用与A上，1表示负数，作用于B上）
// B1表示B玩家应对A玩家出的这张卡的操作回复结算分数，如果B1是0，则默认无操作，如果B1与A1相同分数，则表示这次A操作结果无效
//计算分数处理(卡1的分数+卡2的分数)（累计3张卡，如果没有卡，则默认是0，即没有使用任何卡）
const isEffectCard = (numA1, numA2, numB1, numB2, A1, A2, B1, type, who) => {

    //进入限制卡的逻辑判断
    if (0 < A1 && A1 < type) {
        //
        who.interact.log('我在判断效果卡函数进入判断限制卡逻辑了')
        return [numA1, numA2, numB1, numB2]
        //进入效果卡，装备卡逻辑
    } else {
        //假设A与B的分数一样，两种情况，要么就是0，要么是同一系列，而状态相反的卡（即B卡取消A卡的效果）
        if (A1 == B1) {
            who.interact.log('我在判断效果卡函数判断a1=b1')

            return [numA1, numA2, numB1, numB2]
        } else {

            who.interact.log('我在判断效果卡函数判断A2是否大于0', A2 > 0)

            //A2大于0，则意味着A卡是debuff卡，否则是buff卡
            if (A2 > 0) {
                //这个时候要判断B的积分是正还是负,大于0则是负
                who.interact.log('我在判断效果卡函数判断是debuff卡的情况下判断numb的状态是否大于0', numB2 > 0)

                if (numB2 > 0) {
                    return [numA1, numA2, numB1 + A1, numB2]
                } else {
                    who.interact.log('我在判断效果卡函数判断是debuff卡的情况下判断到b的分数处于正分状态下开始判断够不够扣除分数,', numB1 > A1)

                    //判断B的积分是否够扣除A卡的效果，不够则变负积分状态
                    if (numB1 > A1) {
                        return [numA1, numA2, numB1 - A1, numB2]
                    } else {
                        return [numA1, numA2, A1 - numB1, 1]
                    }
                }
            } else {
                who.interact.log('我在判断效果卡函数判断是buff卡的情况下判断numa的状态是否大于0', numA2 > 0)

                //进入buff卡逻辑.判断A玩家是不是负积分状态，大于0是负分
                if (numA2 > 0) {
                    //大于A1，则代表A玩家负积分不够抵消buff分数,A分状态保持不变
                    who.interact.log('我在判断效果卡函数判断是buff卡的情况下a的负分状态下，判断够不够扣除分数', numA1 > A1)
                    if (numA1 > A1) {
                        return [numA1 - A1, numA2, numB1, numB2]
                    } else {
                        //否则将A玩家的负分变成正分状态
                        return [A1 - numA1, 0, numB1, numB2]
                    }
                } else {
                    //正积分，相加
                    return [numA1 + A1, numA2, numB1, numB2]
                }
            }
        }

    }

}


// 用于计算限制卡的倒计数回合（规则：每个回合内仅允许使用1张限制卡）
// 一个简单的判断，假设卡的结算小于50，则视为限制卡，
// 限制卡效果发动后，每个回合倒计时-1，当值为1的时候，会跳出循环进行结算，倒计时只会延长，没有debuff效果
// 也就是一旦有一个玩家发动了限制卡，一定会产生倒计时（暂时设定，后期修改取消）
const isLimit = (count, limitA, limitB, down) => {
    if (limitA > 0) {
        const sum = limitA + limitB;
        //证明有倒计时了
        if (count > down) {
            const newcount = count - down
            return [newcount + sum]
        } else {
            return [count + sum]
        }
    } else {
        if (count > down) {
            const newcount = count - down
            return [newcount]
        } else {
            return [count]
        }
    }
}





//判断是谁赢了

const decideWinHandle = (HA, FA, FSA, HB, FB, FSB) => {
    if (FSA !== FSB) {
        //进入有正有负的状态
        if (FSA > FSB) {
            //A是负积分的状态,B是正积分的状态下，判断A的隐藏卡能否扣除
            const sumB = HB + FB
            if (HA > FA) {
                const sumA = HA - FA;
                return [sumA, 0, sumB, 0]
            } else {
                const sumA = FA - HA;
                return [sumA, 1, sumB, 0]
            }
        } else {
            //B是负积分的状态,A是正积分的状态下，判断B的隐藏卡能否扣除
            const sumA = HA + FA
            if (HB > FB) {
                const sumB = HB - FB;
                return [sumA, 0, sumB, 0]
            } else {
                const sumB = FB - HB;
                return [sumA, 0, sumB, 1]
            }
        }
    } else {
        //这里FSA与FSB是相等的
        //大于0，证明都是负状态
        if (FSA > 0) {
            //先判断A
            if (HA > FA) {
                const sumA = HA - FA;

                if (HB > FB) {
                    const sumB = HB - FB;
                    return [sumA, 0, sumB, 0]
                } else {
                    const sumB = FB - HB;
                    return [sumA, 0, sumB, 1]
                }
            } else {
                const sumA = FA - HA;
                if (HB > FB) {
                    const sumB = HB - FB;
                    return [sumA, 1, sumB, 0]
                } else {
                    const sumB = FB - HB;
                    return [sumA, 1, sumB, 1]
                }

            }
        } else {
            const sumA = FA + HA;
            const sumB = FB + HB;
            return [sumA, 0, sumB, 0]
        }
    }

}




export const main = Reach.App(
    {},
    [Participant('Oneself', Oneself), Participant('Opponent', Opponent)],
    (A, B) => {
        //每次执行查询超时处理
        const payTimeoutHandle = () => {
            each([A, B], () => {
                interact.payTimeoutHandle();
            });
        };

        //只执行一次
        A.only(() => {
            //转换成自然数
            const wager = declassify(interact.wager)
        });
        //公开这个自然数，并且自己支付这个数量的代币
        A.publish(wager).pay(wager);
        //提交共识
        commit();
        //对手进入房间的时候进行处理获取代币数量处理返回来交互界面以及支付代币
        B.only(() => {
            //前端交互
            interact.getTokenNumberHandle(wager)
        });
        //对手在支付的时候，关闭A的超时处理
        B.pay(wager).timeout(OVERTIME_PAY, () => closeTo(A, payTimeoutHandle))
        //对手提交共识
        commit();
        //告诉玩家的等待状态结束，准备开始游戏
        each([A, B], () => {
            interact.tellGameStartStatus(true)
        });
        //每次执行查询超时处理
        const waitInformTimeout = () => {
            each([A, B], () => {
                interact.waitTimeoutHandle();
            });
        };

        //A玩家进行随机数


        B.only(() => {
            const _startResultB = interact.getHideRoleHandle();
            const [_commitB, _saltB] = makeCommitment(interact, _startResultB);
            const commitB = declassify(_commitB);
            const countB = declassify(interact.setInitialHand());

        });
        B.publish(commitB, countB).timeout(OVERTIME_PLAY, () => closeTo(A, waitInformTimeout));
        commit();

        B.interact.log('B提交了隐藏数据');
        A.only(() => {
            //前端交互
            const _startResultA = interact.getHideRoleHandle();
            const [_commitA, _saltA] = makeCommitment(interact, _startResultA);
            const commitA = declassify(_commitA);
            const countA = declassify(interact.setInitialHand());
        });
        A.publish(commitA, countA).timeout(OVERTIME_PLAY, () => closeTo(B, waitInformTimeout));
        // commit();
        // transfer(2*tokenNum).to(startResultA>startResultB?A:B)
        // commit();
        // exit();
        A.interact.log('A提交了隐藏数据');

        //B玩家进行随机数

        // -------------------------以上随机逻辑验证正确,可以编译输出------------------------------------
        //result是否进行最终计算（0是决定翻牌进行结算），
        //countDown 限制卡的的效果倒计数
        //playCurrent回合数（递增1），FractionA A玩家的分数 FractionB B玩家的分数，
        //FractionAMode表示玩家的积分状态（是正还是负），0是正，1是负
        //playKeyNum 恒定1，用来回合数除以这个取余数计算
        //flagKeyNum 恒定0，用来判断余数是否大于0，大于0则判断为B玩家的回合，否则则是A玩家的回合
        //TruthA, TruthB 玩家A，B各自预言的真相，用来影响判断胜负的关键字
        var [result, countDown, playCurrentNumber, FractionA, FractionAMode, FractionB, FractionBMode, playKeyNum, flagKeyNum, TruthA, TruthB, type] = [1, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 50];
        // FALGA && FALGB 定义这两个是为了解决 前端
        invariant(countA && countB && balance() == 2 * wager);

        while (result > 0 && countDown !== countA && countDown !== countB) {

            //同步更新回合状态
            each([A, B], () => {
                interact.tellEndRoundStatus(FractionA, FractionAMode, FractionB, FractionBMode, playCurrentNumber, countDown);
            });

            //计算回合数是谁在操作，默认是A是第一回合
            const flagnumber = playCurrentNumber % playKeyNum;
            //判断不是第一个回合，并且有倒计数

            //如果等于0，说明是偶数回合，不等于0说明是奇数回合
            if (flagnumber !== flagKeyNum) {
                commit();
                A.only(() => {
                    // interact.tellPlayRoundNumber(playCurrentNumber)
                    interact.currentDrawCardAction();
                    const [_CA1_uuid, _CA1_num, _CA1_mode, _CA2_uuid, _CA2_num, _CA2_mode, _CA3_uuid, _CA3_num, _CA3_mode, _limitCA_uuid, _limitCA_num, _limitCA_mode, _saidTruthA] = interact.currentUseCardAction();
                    const CA1_uuid = declassify(_CA1_uuid);
                    const CA1_num = declassify(_CA1_num);
                    const CA1_mode = declassify(_CA1_mode);

                    const CA2_uuid = declassify(_CA2_uuid);
                    const CA2_num = declassify(_CA2_num);
                    const CA2_mode = declassify(_CA2_mode);

                    const CA3_uuid = declassify(_CA3_uuid);
                    const CA3_num = declassify(_CA3_num);
                    const CA3_mode = declassify(_CA3_mode);


                    const limitCA_uuid = declassify(_limitCA_uuid);
                    const limitCA_num = declassify(_limitCA_num);
                    const limitCA_mode = declassify(_limitCA_mode);

                    const saidTruthA = declassify(_saidTruthA);
                })
                A.publish(CA1_uuid, CA1_num, CA1_mode, CA2_uuid, CA2_num, CA2_mode, CA3_uuid, CA3_num, CA3_mode, limitCA_uuid, limitCA_num, limitCA_mode, saidTruthA);
                A.interact.log('A公布使用卡的情况了')
                commit();
                B.only(() => {
                    //等待B玩家的回应操作（_replyUseCard判断B对A的效果卡处理结果，_replyResultB回应A的处理翻牌意见）
                    const [_RB1_uuid, _RB1_num, _RB1_mode, _RB2_uuid, _RB2_num, _RB2_mode, _RB3_uuid, _RB3_num, _RB3_mode, _RBlimit_uuid, _RBlimit_num, _RBlimit_mode] = interact.waitUseCardAction(CA1_uuid, CA2_uuid, CA3_uuid, limitCA_uuid, saidTruthA);

                    const RB1_uuid = declassify(_RB1_uuid);
                    const RB1_num = declassify(_RB1_num);
                    const RB1_mode = declassify(_RB1_mode);

                    const RB2_uuid = declassify(_RB2_uuid);
                    const RB2_num = declassify(_RB2_num);
                    const RB2_mode = declassify(_RB2_mode);


                    const RB3_uuid = declassify(_RB3_uuid);
                    const RB3_num = declassify(_RB3_num);
                    const RB3_mode = declassify(_RB3_mode);


                    const RBlimit_uuid = declassify(_RBlimit_uuid);
                    const RBlimit_num = declassify(_RBlimit_num);
                    const RBlimit_mode = declassify(_RBlimit_mode);

                });
                B.publish(RB1_uuid, RB1_num, RB1_mode, RB2_uuid, RB2_num, RB2_mode, RB3_uuid, RB3_num, RB3_mode, RBlimit_uuid, RBlimit_num, RBlimit_mode);
                // B.interact.log('B玩家公布了反击卡了')
                //通知A玩家，B玩家出卡的结果
                A.interact.tellwaitplayerUseCardResult(RB1_uuid, RB2_uuid, RB3_uuid, RBlimit_uuid);

                const [FA1, FAM1, FB1, FBM1] = isEffectCard(FractionA, FractionAMode, FractionB, FractionBMode, CA1_num, CA1_mode, RB1_num, type, A);

                const [FA2, FAM2, FB2, FBM2] = isEffectCard(FA1, FAM1, FB1, FBM1, CA2_num, CA2_mode, RB2_num, type, A);
                // A.interact.log('A用卡后最终结果是',FA2, FAM2, FB2, FBM2)

                const [FA3, FAM3, FB3, FBM3] = isEffectCard(FA2, FAM2, FB2, FBM2, CA3_num, CA3_mode, RB3_num, type, A);

                const [newcountdown] = isLimit(countDown, limitCA_num, RBlimit_num, countA);

                [countDown, playCurrentNumber, FractionA, FractionAMode, FractionB, FractionBMode, TruthA] = [newcountdown, playCurrentNumber + 1, FA3, FAM3, FB3, FBM3, saidTruthA];
                continue;
            } else {

                commit();
                B.only(() => {
                    // interact.tellPlayRoundNumber(playCurrentNumber)
                    interact.currentDrawCardAction();
                    const [_CB1_uuid, _CB1_num, _CB1_mode, _CB2_uuid, _CB2_num, _CB2_mode, _CB3_uuid, _CB3_num, _CB3_mode, _limitCB_uuid, _limitCB_num, _limitCB_mode, _saidTruthB] = interact.currentUseCardAction();
                    const CB1_uuid = declassify(_CB1_uuid);
                    const CB1_num = declassify(_CB1_num);
                    const CB1_mode = declassify(_CB1_mode);

                    const CB2_uuid = declassify(_CB2_uuid);
                    const CB2_num = declassify(_CB2_num);
                    const CB2_mode = declassify(_CB2_mode);

                    const CB3_uuid = declassify(_CB3_uuid);
                    const CB3_num = declassify(_CB3_num);
                    const CB3_mode = declassify(_CB3_mode);

                    const limitCB_uuid = declassify(_limitCB_uuid);
                    const limitCB_num = declassify(_limitCB_num);
                    const limitCB_mode = declassify(_limitCB_mode);

                    const saidTruthB = declassify(_saidTruthB);
                })
                B.publish(CB1_uuid, CB1_num, CB1_mode, CB2_uuid, CB2_num, CB2_mode, CB3_uuid, CB3_num, CB3_mode, limitCB_uuid, limitCB_num, limitCB_mode, saidTruthB);
                // B.interact.log('B公布使用卡的情况了')
                commit();

                A.only(() => {
                    //等待a玩家的回应操作（_replyUseCard判断B对A的效果卡处理结果，_replyResultB回应A的处理翻牌意见）
                    const [_RA1_uuid, _RA1_num, _RA1_mode, _RA2_uuid, _RA2_num, _RA2_mode, _RA3_uuid, _RA3_num, _RA3_mode, _RAlimit_uuid, _RAlimit_num, _RAlimit_mode] = interact.waitUseCardAction(CB1_uuid, CB2_uuid, CB3_uuid, limitCB_uuid, saidTruthB);

                    const RA1_uuid = declassify(_RA1_uuid);
                    const RA1_num = declassify(_RA1_num);
                    const RA1_mode = declassify(_RA1_mode);

                    const RA2_uuid = declassify(_RA2_uuid);
                    const RA2_num = declassify(_RA2_num);
                    const RA2_mode = declassify(_RA2_mode);


                    const RA3_uuid = declassify(_RA3_uuid);
                    const RA3_num = declassify(_RA3_num);
                    const RA3_mode = declassify(_RA3_mode);


                    const RAlimit_uuid = declassify(_RAlimit_uuid);
                    const RAlimit_num = declassify(_RAlimit_num);
                    const RAlimit_mode = declassify(_RAlimit_mode);

                });
                A.publish(RA1_uuid, RA1_num, RA1_mode, RA2_uuid, RA2_num, RA2_mode, RA3_uuid, RA3_num, RA3_mode, RAlimit_uuid, RAlimit_num, RAlimit_mode);
                //通知b玩家，a玩家出卡的结果
                // A.interact.log('A玩家公布了反击卡了')

                B.interact.tellwaitplayerUseCardResult(RA1_uuid, RA2_uuid, RA3_uuid, RAlimit_uuid);

                const [FB1, FBM1, FA1, FAM1] = isEffectCard(FractionB, FractionBMode, FractionA, FractionAMode, CB1_num, CB1_mode, RA1_num, type, B);
                const [FB2, FBM2, FA2, FAM2] = isEffectCard(FB1, FBM1, FA1, FAM1, CB2_num, CB2_mode, RA2_num, type, B);
                const [FB3, FBM3, FA3, FAM3] = isEffectCard(FB2, FBM2, FA2, FAM2, CB3_num, CB3_mode, RA3_num, type, B);

                const [newcountdown] = isLimit(countDown, limitCB_num, RAlimit_num, countB);


                [countDown, playCurrentNumber, FractionA, FractionAMode, FractionB, FractionBMode, TruthB] = [newcountdown, playCurrentNumber + 1, FA3, FAM3, FB3, FBM3, saidTruthB];
                continue;
            }


        }
        commit();

        //让A玩家解密他的随机数
        A.only(() => {
            const [saltA, startResultA] = declassify([_saltA, _startResultA]);
        });
        A.publish(saltA, startResultA);
        //验证签名是否一致
        checkCommitment(commitA, saltA, startResultA);
        commit();
        //让B玩家解密他的随机数
        B.only(() => {
            const [saltB, startResultB] = declassify([_saltB, _startResultB]);
        });
        B.publish(saltB, startResultB);
        //验证签名是否一致
        checkCommitment(commitB, saltB, startResultB);


        const [sumA, sumA_s, sumB, sumB_s] = decideWinHandle(startResultA, FractionA, FractionAMode, startResultB, FractionB, FractionBMode)

        if (sumA == sumB && sumA_s == sumB_s) {
            //进入平局处理(暂时设定是A赢)
            transfer(2 * wager).to(A);
        } else {
            if (sumA_s > sumB_s) {
                //判断是B赢了
                transfer(2 * wager).to(B);
            } else {
                if (sumA_s == sumB_s) {
                    if (sumA_s > 0) {
                        transfer(2 * wager).to(sumA > sumB ? B : A);
                    } else {
                        // 都是正
                        transfer(2 * wager).to(sumA > sumB ? A : B);
                    }
                } else {
                    transfer(2 * wager).to(A);
                }
            }
        }

        commit();

        each([A, B], () => {
            interact.tellWhoWinHandle(sumA, sumA_s, sumB, sumB_s);
        });

        exit();


    });
